﻿using Microsoft.Xna.Framework.Graphics;
using System.Collections.Generic;
using PenguinForce.Entities;
using Microsoft.Xna.Framework;
using System;
using PenguinForce.Collisions;
using Microsoft.Xna.Framework.Content;
using PenguinForce.Behaviors;
using PenguinForce.FlockBehaviors;

namespace PenguinForce
{
    /// <summary>
    /// This class manages all the birds in the flock and handles 
    /// their update and draw
    /// </summary>
    public class Flock
    {
        #region Constants

        private const int SPAWN_RADIUS = 400;

        #endregion

        #region Variables

        int _flockSize;

        Random random = new Random();

        private ContentManager _content;

  

        /// <summary>
        /// List of Flock Members
        /// </summary>
        public List<Penguin> flock;

        private FlockMaster _master;

        /// <summary>
        /// Parameters flock members use to move and think
        /// </summary>
        public AIParameters FlockParams
        {
            set
            {
                flockParams = value;
            }
        }
        protected AIParameters flockParams;

        public int Count
        {
            get
            {
                return flock.Count;
            }
        }

        #endregion

        #region Initialization

        /// <summary>
        /// Setup the flock boundaries and generate individual members of the flock
        /// </summary>
        /// <param name="theTex">Texture to use for flock members</param>
        /// <param name="screenSize">screen size</param>
        /// <param name="flockParameters">Behavior parameters for the flock</param>
        public Flock(int flockSize, ContentManager content, Texture2D waypointTexture, AIParameters flockParameters)
        {
            _flockSize = flockSize;

            this._content = content;

            flock = new List<Penguin>();
            flockParams = flockParameters;

            // places the tank halfway between the center of the screen and the upper left corner
            _master = new FlockMaster(content);
            _master.Reset(CollisionManager.Instance.GetCurrentLevel().m_startLocation);
            _master.LoadContent(content);
           
            ResetFlock();
        }
        #endregion

        #region Update and Draw
        /// <summary>
        /// Update each flock member, Each bird want to fly with or flee from everything
        /// it sees depending on what type it is
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        /// <param name="theCat"></param>
        public void Update(GameTime gameTime, IAbilityController abilityController)
        {
            _master.Update(gameTime);

            CollisionManager.Instance.ResetWeakenedIce();
            foreach (Penguin penguin in new List<Penguin>(flock))
            {
                penguin.ResetThink();

                foreach (Penguin theOtherBird in new List<Penguin>(flock))
                {
                    //this check is so we don't try to fly to ourself!
                    if (penguin != theOtherBird)
                    {
                        penguin.ReactTo(theOtherBird, ref flockParams);
                    }
                }

                if (abilityController.IsSirenTriggered)
                {
                    penguin.Behaviors.Clear();
                    FlockBehaviors.Behaviors birdReactions = new FlockBehaviors.Behaviors();
                    birdReactions.Add(new FleeBehavior(penguin));
                    penguin.Behaviors.Add(EntityType.Bird, birdReactions);

                }
                else if (penguin.Behaviors.Count == 1)
                {
                    penguin.Behaviors.Clear();
                    penguin.BuildBehaviors();
                }
                else
                {
                    //Look for the cat
                    penguin.ReactTo(_master, ref flockParams);
                }

                penguin.Update(gameTime, ref flockParams);
            }
            CollisionManager.Instance.BreakIce();
        }

        /// <summary>
        /// Calls Draw on every member of the Flock
        /// </summary>
        /// <param name="spriteBatch"></param>
        /// <param name="gameTime"></param>
        public void Draw(SpriteBatch spriteBatch, GameTime gameTime)
        {
            _master.Draw(spriteBatch, gameTime);
            foreach (Penguin theBird in flock)
            {
                theBird.Draw(spriteBatch, gameTime);
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Clear the current flock if it exists and randomly generate a new one
        /// </summary>
        public void ResetFlock()
        {
            flock.Clear();
            flock.Capacity = _flockSize;

            Penguin tempBird;
            Vector2 tempDir;
            Vector2 tempLoc;

            for (int i = 0; i < _flockSize; i++)
            {
                tempLoc = GetSpawnPoint(); // new Vector2((float)random.Next(_boundaryWidth), (float)random.Next(_boundaryHeight));
                tempDir = new Vector2((float)random.NextDouble() - 0.5f, (float)random.NextDouble() - 0.5f);
                tempDir.Normalize();

                tempBird = new Penguin(_content, tempDir, tempLoc);
                while (CollisionManager.Instance.ContainsBarrier(tempBird) || CollisionManager.Instance.ContainsEntity(tempBird))
                {
                    tempBird.Location = GetSpawnPoint(); // new Vector2((float)random.Next(_boundaryWidth), (float)random.Next(_boundaryHeight));
                }
                Spawn(tempBird);
            }
        }

        private Vector2 GetSpawnPoint()
        {
            return new Vector2(
                (float)random.Next((int)_master.Location.X - SPAWN_RADIUS, (int)_master.Location.X + SPAWN_RADIUS),
                (float)random.Next((int)_master.Location.Y - SPAWN_RADIUS, (int)_master.Location.Y + SPAWN_RADIUS)
            );
        }

        public void Spawn(Penguin entity)
        {
            flock.Add(entity);
            CollisionManager.Instance.Entities.Add(entity);
        }

        public void Kill(Penguin entity)
        {
            if (!flock.Contains(entity))
            {
                return; // you can't die if you never lived
            }
            flock.Remove(entity);
            CollisionManager.Instance.Entities.Remove(entity);
        }

        public void Clear()
        {
            flock.Clear();
        }

        public void AddWaypoint(Vector2 location)
        {
            _master.Waypoints.Enqueue(location);
        }

        public void ClearWaypoints()
        {
            _master.Reset();
        }

        #endregion
    }
}